package com.itelite.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itelite.common.info.RedisKey;
import com.itelite.common.util.FileUtils;
import com.itelite.common.util.SecurityUtils;
import com.itelite.config.WebAppConfig;
import com.itelite.domain.dto.Diversion;
import com.itelite.domain.dto.GroupMemberParam;
import com.itelite.domain.dto.UserVo;
import com.itelite.domain.pojo.Group;
import com.itelite.mapper.GroupMapper;
import com.itelite.mapper.UserMapper;
import com.itelite.service.GroupService;
import com.itelite.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 沈洋 邮箱:1845973183@qq.com
 * @create 2021/8/7-16:50
 **/
@Service
@Slf4j
public class GroupServiceImpl implements GroupService {
    @Autowired
    private RedisService redisService;
    @Autowired
    private GroupMapper groupMapper;
    @Autowired
    private UserMapper userMapper;
    @Override
    public Group getGroupTree() {
        Group groupTree  = (Group) redisService.getValue(RedisKey.GROUP_TREE);
        //缓存存在
        if(!ObjectUtils.isEmpty(groupTree)){
            return groupTree;
        }
        //缓存失效
        List<Group> groupList  = groupMapper.queryGroupList();
        Group root = makeTree(groupList);
        //重新写入缓存
        redisService.cacheValue(RedisKey.GROUP_TREE,root);
        return root;
    }

    @Override
    public String queryGroupNameByGroupId(Integer groupId) {
        return groupMapper.queryGroupNameByGroupId(groupId);
    }

    @Override
    public Integer queryGroupIdByUserId(Integer userId) {
        return groupMapper.queryGroupIdByLeaderId(userId);
    }

    /**
     * 获取小组组名
     */
    @Override
    public String[] getGroupLeafNode() {
        List<Group> list = groupMapper.querySimpleGroupList(null);
        HashMap<Integer,Group> map = new HashMap<>();
        list.forEach(l->{
            map.put(l.getGroupId(),l);
        });
        list.forEach(l->{
            map.remove(l.getParentId());
        });
        String[] s = new String[map.size()];
        AtomicInteger i = new AtomicInteger(0);
        map.forEach((k,v)->{
            s[i.getAndIncrement()]=v.getGroupName();
        });
        return s;
    }

    @Override
    public String[] getImportableGroup() {
        List<Group> groups = groupMapper.queryImportableGroup(1);
        List<Group> userGroups = getUserControlGroupList();
        if(CollectionUtils.isEmpty(userGroups)||CollectionUtils.isEmpty(groups)) return null;
        for (int i = 0; i < userGroups.size(); i++) {
            boolean flag = false;
            for (Group group : groups) {
                if(group.getGroupId().equals(userGroups.get(i).getGroupId())){{
                    flag=true;
                    break;
                }}
            }
            if(!flag){
                userGroups.remove(i);
                i--;
            }
        }
        String[] s = new String[userGroups.size()];
        for (int i = 0; i < s.length; i++) {
            s[i]=userGroups.get(i).getGroupName();
        }
        return s;
    }

    @Override
    public List<Group> getImportableGroup1() {
        return groupMapper.queryImportableGroup(null);
    }

    @Override
    public List<Group> getGroups() {
        return groupMapper.queryGroupList();
    }

    @Override
    public PageInfo<UserVo> queryGroupMember(GroupMemberParam param) {
        Integer groupId = param.getGroupId();
        Integer[] groupIds = getGroupIds(groupId);
        if(ArrayUtils.isEmpty(groupIds))return null;
        param.setGroupIds(groupIds);
        PageHelper.startPage(param.getPageNum(),param.getPageSize());
        List<UserVo> members = groupMapper.queryGroupMember(param);
        return new PageInfo<>(members);
    }

    @Override
    public Group getUserControlGroup() {
        Integer userId = SecurityUtils.getUserId();
        return getGroupRoot(groupMapper.queryGroupIdByLeaderId(userId));
    }

    @Override
    public List<Group> getUserControlGroupList() {
        Group root = getUserControlGroup();
        if(root==null) return null;
        List<Group> result = new ArrayList<>();
        Queue<Group> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Group g = queue.poll();
                assert g!=null;
                result.add(g);
                queue.addAll(g.getChildren());
            }
        }
        return result;
    }

    private Group makeTree(List<Group> groupList){
        Group root = null;
        for (Group group : groupList) {
            if (group.getParentId()!=0) {
                int parentId = group.getParentId();
                    for (Group g : groupList) {
                        if (g.getGroupId()==parentId) {
                            g.getChildren().add(group);
                            break;
                        }
                }
            }else root=group;
        }
        return root;
    }
    public Group getGroupRoot(Integer targetGroupId) {
        Group root = getGroupTree();
        if(targetGroupId==null) return null;
        Queue<Group> queue =  new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Group p = queue.poll();
                assert p != null;
                if(p.getGroupId().equals(targetGroupId)) return p;
                else {
                    queue.addAll(p.getChildren());
                }
            }
        }
        return null;
    }

    @Override
    public boolean addGroup(Map<String,Object> params) throws IOException {
        Group parentGroup = getGroupRoot((Integer) params.get("parentId"));
        Group lastGroup=parentGroup.getChildren().size()>0?parentGroup.getChildren().get(parentGroup.getChildren().size()-1):parentGroup;
        int level = parentGroup.getLevel();
        int lastNodeId=lastGroup.getGroupId();
        if(level==1){
            params.put("groupId",lastNodeId+1000);
        }else if(level==2){
            params.put("groupId",lastNodeId+10);
        }else params.put("groupId",lastNodeId+1);
        //设置默认图片
        String root = System.getProperty("user.dir");
        File src = new File(root,WebAppConfig.IT_IMAGE_URL);
        File des = new File(root,File.separator+WebAppConfig.ROOT_DIR_COVER+File.separator+params.get("groupId")+".jpg");
        org.apache.commons.io.FileUtils.copyFile(src,des);
        params.put("image",WebAppConfig.IT_IMAGE_URL.replace("10000",params.get("groupId").toString()));
        int row = groupMapper.insertGroup(params);
        //清空缓存
        if(row>0&&redisService.removeValue(RedisKey.GROUP_TREE)){
            log.info(SecurityUtils.getUsername()+"新增小组："+params.get("groupName"));
            return true;
        }
        return false;
    }

    @Override
    public boolean updateGroup(Group group, MultipartFile file) {
        log.info(SecurityUtils.getUsername()+"修改"+group.getGroupName()+"信息");
        int row = 0;
        boolean flag = false;
        if(group.getGroupName()!=null||group.getGroupDetail()!=null||group.getTeacherId()!=null){
            row = groupMapper.updateGroup(group);
            if(row>0) flag=true;
        }
        //更新成功
        //更新图片
        if (file != null && !file.isEmpty()&&FileUtils.imageExtensionName.contains(file.getContentType())) {
            //上传图片
            File coverDir = FileUtils.createDir(WebAppConfig.ROOT_DIR_COVER);
            //插入文件信息到数据库中
            String fileName = group.getGroupId()+".jpg";
            File desFile = new File(coverDir, fileName);
            try {
                file.transferTo(desFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (groupMapper.updateGroupImage(group.getGroupId(), File.separator+ WebAppConfig.ROOT_DIR_COVER+File.separator+desFile.getName())>0) {
                flag=true;
            }
        }
        //更新组长
        if(group.getLeaderIds()!=null&&group.getLeaderIds().length!=0){
            log.info(group.getGroupName()+"组长信息发生变更");
            Integer[] oldLeaderIds = groupMapper.queryGroupLeaderIds(group.getGroupId());
            Integer[] updateIds = checkNotIn(group.getLeaderIds(),oldLeaderIds);
            Integer[] insertIds = checkNotIn(oldLeaderIds,group.getLeaderIds());
            if(updateIds.length>0){
                groupMapper.updateOldLeaderState(group.getGroupId(),updateIds);
                flag=true;
            }
            if(insertIds.length>0&&groupMapper.insertGroupLeader(group.getGroupId(),insertIds)>0){
                flag=true;
                //将新增组长权限设置为User/ADMIN
                String role = group.getGroupId()==10000?"ROLE_ADMIN":"ROLE_USER";
                userMapper.updateUserRole(role,insertIds);
            }
        }
        //清空Redis
        redisService.removeValue(RedisKey.GROUP_TREE);
        return row>0;
    }
    private Integer[] checkNotIn(Integer[] target, Integer[] source) {
        List<Integer> re = new ArrayList<>();
        for (Integer i : source) {
            boolean flag = true;
            for (Integer j : target) {
                if(j.equals(i)){
                    flag=false;
                    break;
                }
            }
            if(flag)re.add(i);
        }
        Integer[] result = new Integer[re.size()];
        result = re.toArray(result);
        return result;
    }
    public Integer[] getGroupIds(int groupId) {
        Group root = getGroupRoot(groupId);
        if(root==null) return null;
        ArrayList<Integer> list = new ArrayList<>();
        Queue<Group> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Group p = queue.poll();
                assert p != null;
                list.add(p.getGroupId());
                queue.addAll(p.getChildren());
            }
        }
        Integer[] groups = new Integer[list.size()];
        list.toArray(groups);
        return groups;
    }

    @Override
    public boolean deleteGroup(Integer groupId) {
        Integer[] groupIds = getGroupIds(groupId);
        if(!ArrayUtils.isEmpty(groupIds)){
            int row = groupMapper.updateGroupState(groupIds);
            if(row>0){
                //将小组成员账号全部重置
                userMapper.abandonedGroupUser(groupIds);
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean diversionGroup(Diversion diversion) {
        return userMapper.updateUserGroupId(diversion)>0;
    }

    @Override
    public List<Group> getSendEmailGroup() {
        return groupMapper.queryIsSendEmailGroup();
    }

    @Override
    public void updateGroupSendState(Integer groupId, Integer state) {
        groupMapper.updateGroupSendState(groupId,state);
    }

    @Override
    public void updateGroupImportable(Integer groupId, Integer state) {
        groupMapper.updateGroupImportable(groupId,state);
    }

    @Override
    public String getGroupName(Integer groupId) {
        return groupMapper.queryGroupName(groupId);
    }
}
